<template>
  <div class="write-article pb-4 pt-4">
    <div id="markdown-container"></div>
    <div class="article-setting p-5">
      <p>发布设置</p>
      <el-form :model="articleForm" :rules="articleRules" ref="formRef">
        <el-form-item label="添加封面" prop="image">
          <el-upload
            class="image-uploader"
            :action="uploadUrl"
            :show-file-list="false"
            :data="uploadData"
            :on-success="handleImageSuccess"
            :on-error="handleImagerError"
            :before-upload="beforeImageUpload"
          >
            <img v-if="articleForm.image" :src="imageUrl" class="image" />
            <el-icon v-else class="image-uploader-icon"><Plus /></el-icon>
          </el-upload>
        </el-form-item>
        <el-form-item label="文章标题" prop="title">
          <el-input
            v-model="articleForm.title"
            size="large"
            placeholder="请输入标题（最多100个字）"
            maxlength="100"
          />
        </el-form-item>
      </el-form>
      <div class="text-center">
        <el-button type="primary" @click="publish">发布</el-button>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import {
  ElMessage,
  ElForm,
  ElFormItem,
  ElUpload,
  ElIcon,
  ElInput,
  UploadProps,
  FormRules,
  ElButton,
  FormInstance,
} from 'element-plus'
import { defineComponent, onMounted, ref, reactive, computed } from 'vue'
import Cherry from 'cherry-markdown'
import CherryEngine from 'cherry-markdown/dist/cherry-markdown.engine.core'
import 'cherry-markdown/dist/cherry-markdown.min.css'
import { uploadFile } from '@/services/ApiServer/CommonRequest'
import { Plus } from '@element-plus/icons-vue'
import { RequestError, RequestDto } from '@/services/ApiServer/request'
import { UploadDto } from '@/services/ApiServer/CommonRequest'
import { useUserStore } from '@/store/user'
import { useGlobalStore } from '@/store/global'
import { createArticle, updateArticle, getArticleDetail } from '@/services/ApiServer/ArticleRequest'
import { useRoute, useRouter } from 'vue-router'
import { userInfo } from 'os'

export default defineComponent({
  name: 'writeArticle',
  components: {
    ElForm,
    ElFormItem,
    ElUpload,
    ElIcon,
    ElInput,
    Plus,
    ElButton,
  },
  setup() {
    const route = useRoute()
    const router = useRouter()
    const articleId = computed(() => {
      return route.query.id as string | undefined
    })
    const getArticle = async () => {
      if (articleId.value) {
        const res = await getArticleDetail(articleId.value)
        if (res && res.code === 0 && res.data) {
          const cherryEngineInstance = new CherryEngine({})
          articleForm.content = cherryEngineInstance.makeMarkdown(res.data.content)
          articleForm.image = res.data.image?._id || ''
          articleForm.title = res.data.title
          imageUrl.value = res.data.image?.url || ''
        }
      }
    }

    // cherry markdown
    let cherryInstance: null | Cherry = null
    const fileUpload = async (file: File) => {
      if (file.size / 1024 > 500) {
        ElMessage.warning('上传图片不能超过500KB！')
        return
      }
      if (!/^image\/(jpeg|png|jpg)$/.test(file.type)) {
        ElMessage.warning('请上传JPG/PNG格式图片！')
        return
      }
      const formData = new FormData()
      formData.append('file', file)
      const res = await uploadFile(formData)
      if (res && res.code === 0) {
        const fileType = file.type.split('/')[0]
        let insertStr = ''
        switch (fileType) {
          case 'image':
            insertStr = `![${file.name}](${res.data.url})`
            break
          case 'audio':
            insertStr = `!audio[${file.name}](${res.data.url})`
            break
          case 'video':
            insertStr = `!video[${file.name}](${res.data.url})`
            break
          default:
            break
        }
        insertStr && (cherryInstance as Cherry).insert(insertStr)
      }
    }
    const userStore = useUserStore()
    let imageUrl = ref('')
    let articleForm = reactive({
      title: '',
      content: '',
      image: '',
      column: userStore.userInfo?.column || '',
      author: userStore.userInfo?._id || '',
    })
    const articleRules: FormRules = {
      title: [{ required: true, message: '请填写标题', trigger: 'blur' }],
      image: [{ required: true, message: '请上传封面', trigger: 'change' }],
    }
    const uploadUrl = `${import.meta.env.VITE_APP_SERVER}upload`
    const uploadData = {
      icode: import.meta.env.VITE_APP_ICODE,
    }
    const handleImageSuccess: UploadProps['onSuccess'] = (
      response: RequestDto<UploadDto>,
      uploadFile
    ) => {
      if (response.code === 0 && uploadFile.raw) {
        imageUrl.value = URL.createObjectURL(uploadFile.raw)
        articleForm.image = response.data._id
      }
    }
    // 上传失败钩子
    const handleImagerError: UploadProps['onError'] = (error) => {
      const response: RequestError = JSON.parse(error.message)
      ElMessage.error(response.error)
    }
    const beforeImageUpload: UploadProps['beforeUpload'] = (rawFile) => {
      if (rawFile.size / 1024 > 500) {
        ElMessage.warning('上传图片不能超过500KB！')
        return false
      }
      if (!/^image\/(jpeg|png|jpg)$/.test(rawFile.type)) {
        ElMessage.warning('请上传JPG/PNG格式图片！')
        return false
      }
      return true
    }
    const formRef = ref<FormInstance | null>()
    const globalStore = useGlobalStore()
    const publish = () => {
      formRef.value?.validate(async (valid) => {
        if (valid && cherryInstance) {
          articleForm.content = cherryInstance.getHtml()
          const content = cherryInstance.getMarkdown()
          if (!content || content === '请输入正文...') {
            ElMessage.warning('请填写文章内容！')
            return
          }
          globalStore.setLoading(true)
          const res = articleId.value
            ? await updateArticle(articleId.value, articleForm)
            : await createArticle(articleForm)
          if (res && res.code === 0 && res.data) {
            ElMessage.success('发布成功！')
            router.push(`/column/detail/${userStore.userInfo?.column}/${res.data._id}`)
          }
          globalStore.setLoading(false)
        }
      })
    }
    onMounted(async () => {
      await getArticle()
      cherryInstance = new Cherry({
        id: 'markdown-container',
        value: articleForm.content || '请输入正文...',
        toolbars: {
          theme: 'light',
          toolbar: [
            'bold',
            'italic',
            'strikethrough',
            '|',
            'color',
            'header',
            '|',
            'list',
            {
              insert: [
                'image',
                'link',
                'hr',
                'br',
                'code',
                'formula',
                'toc',
                'table',
                'line-table',
                'bar-table',
              ],
            },
            'graph',
            'settings',
          ],
        },
        editor: {
          height: 'calc(100% - 350px)',
        },
        fileUpload,
      })
    })
    return {
      uploadUrl,
      imageUrl,
      articleForm,
      articleRules,
      uploadData,
      formRef,
      articleId,
      handleImageSuccess,
      beforeImageUpload,
      handleImagerError,
      publish,
    }
  },
})
</script>

<style lang="scss" scoped>
.write-article {
  height: calc(100vh - 116px);
  max-width: 1200px;
  min-width: 1000px;
  margin: 0 auto;
  .article-setting {
    .image-uploader {
      .image {
        width: 178px;
        height: 178px;
        display: block;
      }
      ::v-deep(.el-upload) {
        border: 1px dashed var(--el-border-color);
        border-radius: 6px;
        cursor: pointer;
        position: relative;
        overflow: hidden;
        transition: var(--el-transition-duration-fast);
        &:hover {
          border-color: var(--el-color-primary);
        }
        .el-icon.image-uploader-icon {
          font-size: 28px;
          color: #8c939d;
          width: 178px;
          height: 178px;
          text-align: center;
        }
      }
    }
    ::v-deep(.el-form-item) {
      .el-input__wrapper {
        box-shadow: 0 -1px var(--el-input-border-color, var(--el-border-color)) inset;
        border-radius: unset;
        background: transparent;
      }
      &.is-error .el-input__wrapper {
        box-shadow: 0 -1px var(--el-color-danger) inset;
      }
    }
  }
}
</style>
